#!/bin/sh

# compile.sh的中文版本
# 翻译By tzdtwsj.

#|| goto :windows_detected
{ # put the whole thing in a block so as not to behave weirdly if interrupted
set -e

# 全局变量:
# CHOICE_BUILDTYPE  - 可选值 "Release" 或 "Debug"
# CHOICE_THREADS    - 一个数字值, 指定make命令时使用的线程数
# CHOICE_BRANCH     - 指定使用的分支, 目前只有 "master".
# STATE_INTERACTIVE - 如果为1, 则以交互式运行该脚本, 0则不是
# STATE_NEW         - Whether this is the first run. If 1, then no GIT repo exists yet. 0 otherwise.

# 常量:
DEFAULT_BUILDTYPE="Release" # 其他选项: "Debug"
DEFAULT_BRANCH="master"     # 其他选项: 目前没有
DEFAULT_THREADS=1

# 不可通过命令行修改的常量:
UPSTREAM_REPO="origin"
UPSTREAM_LINK="https://atomgit.com/flmp-studios/cuberite_flmp"

#=================== 错误函数 ===================


errorCompile ()
{
	echo
	echoInt "-----------------"
	echo "编译失败, 失败的命令:"
	echo "$@"
	exit 1
}

errorGit ()
{
	echo
	echoInt "-----------------"
	echo "代码拉取失败. (检查你的网络连通性). 失败的命令:"
	echo "$@"
	exit 2
}

errorDependencies ()
{
	# The error messages are complex and OS-dependant, and are printed in the dependencies section before this is called.
	exit 3
}

errorArguments ()
{
	echo "用法: ./compile_cn.sh [选项]"
	echo "编译Cuberite. Updates the GIT repository if needed, and downloads it if it does not exist."
	echo "Runs interactively, unless one or more options are specified."
	echo
	echo "选项:"
	echo "  -m  编译模式, 可选\"Release\"或\"Debug\".默认是\"$DEFAULT_BUILDTYPE\""
	echo '  -t  指定编译时使用的线程数'
	echo "      如果未指定, 将会使用默认的线程数$DEFAULT_THREADS, 如果为指定为AUTO, 将会自动"
	echo '      设置编译线程数为CPU的线程数.'
	echo '  -b  编译的分支. (目前不生效并且固定为MASTER)'
	echo '  -n yes: 不使用交互模式'
	echo '          如果某些参数没指定，那么将会设为默认值.'
	echo '  -d yes: Dry run. 输出所选内容然后退出'
	echo
	echo "使用示例:"
	echo "  ./compile_cn.sh"
	echo "  ./compile_cn.sh -m Debug"
	echo "  ./compile_cn.sh -m Release -t 2"
	echo
	echo "返回值: (non 0 returns are accompanied by useful stderr info)"
	echo "0 - 成功              - Success! Code was updated and compiled"
	echo "1 - 编译失败   - cmake, make, or source code issue"
	echo "2 - 代码拉取失败    - Network issue or, far more rarely, a git issue"
	echo "3 - 缺少依赖 - Some compilation tools are missing"
	echo "4 - 参数无效        - Bad commandline arguments were passed"
	echo "5 - 用户输入无效       - Invalid user input in interactive mode"
	echo "6 - 其他                - An error not listed above"
	exit 4
}

errorInput ()
{
	echo
	echoInt "-----------------"
	echo "无法识别的用户输入"
	echo "$@"
	exit 5
}

errorOther ()
{
	echo
	echoInt "-----------------"
	echo "$@"
	exit 6
}


#=================== 回显函数 ===================


echoInt () # echo only if interactive mode.
{
	if [ $STATE_INTERACTIVE -eq 1 ]; then
		echo "$1"
	fi
}

echoErr () # Echo to stderr.
{
	echo "$1" 1>&2
}


#=================== 命令行解析 ===================


STATE_INTERACTIVE=1 # Interactive, unless one or more command line options are passed.
while getopts ":m:t:b:d:n:" name; do
	value=$OPTARG
	STATE_INTERACTIVE=0
	case "$name" in
	m)
		if [ ! -z "$CHOICE_BUILDTYPE" ]; then errorArguments; fi # Argument duplication.
		if [ "$value" = "Debug" ] || [ "$value" = "Release" ]; then
			CHOICE_BUILDTYPE="$value"
		else
			errorArguments
		fi
	;;
	t)
		if [ ! -z "$CHOICE_THREADS" ]; then errorArguments; fi # Argument duplication.
		if [ "$value" -gt 0 ] 2>/dev/null || [ "$value" = "AUTO" ]; then # If a positive integer or the special value "AUTO".
			CHOICE_THREADS="$value"
		else
			errorArguments
		fi
	;;
	b)
		if [ ! -z "$CHOICE_BRANCH" ]; then errorArguments; fi # Argument duplication.
		CHOICE_BRANCH=1 # Only used for dupe checking, overridden below.
		echoErr "警告: 忽略-b参数"
	;;
	d)
		if [ ! -z "$DRY_RUN" ]; then errorArguments; fi # Argument duplication.
		DRY_RUN="yes"
	;;
	n)
		if [ "$dummy" = "1" ]; then errorArguments; fi # Argument duplication.
		dummy=1 # we just want to disable interactive mode, passing an argument already did this. No need to do anything.
	;;
	*)
		errorArguments
	;;
	esac
done

if [ -z "$DRY_RUN" ]; then DRY_RUN="no"; fi

#=================== Dependency checks and greeting ===================


# Do we already have a repo?
checkCuberiteDir ()
{
	[ -d .git ] && [ -f easyinstall.sh ] && [ -f src/BlockArea.cpp ] # A good enough indicator that we're in the Cuberite git repo.
}

STATE_NEW=1
if checkCuberiteDir; then # Check if we're in the Cuberite directory...
	STATE_NEW=0
elif [ -d cuberite ]; then # If there's a directory named "cuberite"...
	cd cuberite_flmp
	if checkCuberiteDir; then # Check if we're in the Cuberite directory...
		STATE_NEW=0
	else
		errorOther "有一个名为'cuberite'的文件夹, 但是没有Cuberite资源存在, 请在其他地方运行该脚本, 或者移动/删除该文件夹."
	fi

fi

if [ $STATE_NEW -eq 0 ]; then
	echoInt "检测到Cuberite存储库, 这将会使编译速度变快, 特别是你如果之前编译过的话."
fi

# Echo: Greetings.
echoInt "

该脚本会下载并编译Cuberite.
如果后面再次运行该脚本，那么会更新Cuberite.
编译和下载将在当前目录中进行.
如果你正在更新，你需要运行: <Path to Cuberite>/compile.sh
从源码编译需要一些时间, 但将会生成运行速度更快的
可执行文件. 如果您更喜欢即用型二进制文件，或者如果您想了解
更多信息，请访问:  https://cuberite.org/"

doDependencyCheck()
{
	MISSING_PACKAGES=""

	# Most distros have the following default compiler names.
	GCC_EXE_NAME="g++"
	CLANG_EXE_NAME="clang"
	COMPILER_PACKAGE_NAME="gcc g++"

	# Most distros have the following package and executable names.
	# Left side: Executable Name, Right side: Package Name. Note that this is SPACE delimited now, unlike in the past.
	PROGRAMS='git git
	make make
	cmake cmake'

	# If any OS deviates from the defaults, we detect the OS here, and change PROGRAMS, COMPILER_PACKAGE_NAME, etc. as needed.

	# Fedora, CentOS, RHEL, Mageia, openSUSE, Mandriva.
	if (rpm --help > /dev/null 2> /dev/null); then
		COMPILER_PACKAGE_NAME="gcc-c++"
	fi

	# Make sure at least one compiler exists.
	GCC_EXISTS=0
	CLANG_EXISTS=0
	$GCC_EXE_NAME --help > /dev/null 2> /dev/null && GCC_EXISTS=1
	$CLANG_EXE_NAME --help > /dev/null 2> /dev/null && CLANG_EXISTS=1
	if [ "$GCC_EXISTS" -eq 0 ] && [ "$CLANG_EXISTS" -eq 0 ]; then
		MISSING_PACKAGES=" $COMPILER_PACKAGE_NAME"
	fi

	# Depdendency check.
	checkPackages ()
	{
		echo "$PROGRAMS" | while read line; do
			EXE_NAME=`echo "$line" | cut -f 1 -d " "`
			PACKAGE_NAME=`echo "$line" | cut -f 2 -d " "`
			command -v $EXE_NAME > /dev/null 2> /dev/null || printf %s " $PACKAGE_NAME"
		done
	}
	MISSING_PACKAGES="$MISSING_PACKAGES`checkPackages`"
	missingDepsExit ()
	{
		if [ "$1" != "" ]; then
			echoErr "你可以安装缺少的依赖，通过:"
			echoErr "$1"
		fi
		echoErr
		echoErr "请安装依赖, 然后回来"# 有点生草，原文:Please install the dependencies, then come back.
		echoErr
		errorDependencies
	}

	if [ "$MISSING_PACKAGES" != "" ]; then
		echoInt
		echoInt "-----------------"
		echoErr "你缺少一些编译依赖:"
		echoErr $MISSING_PACKAGES
		echoErr

		# apt-get guide.
		apt-get --help > /dev/null 2> /dev/null && \
		missingDepsExit "apt-get install$MISSING_PACKAGES"

		# dnf guide.
		dnf --help > /dev/null 2> /dev/null && \
		missingDepsExit "dnf install$MISSING_PACKAGES"

		# zypper guide.
		zypper --help > /dev/null 2> /dev/null && \
		missingDepsExit "zypper install$MISSING_PACKAGES"

		# pacman guide.
		pacman --help > /dev/null 2> /dev/null && \
		missingDepsExit "pacman -S$MISSING_PACKAGES"

		# urpmi guide.
		urpmi --help > /dev/null 2> /dev/null && \
		missingDepsExit "urpmi$MISSING_PACKAGES"

		missingDepsExit ""
	fi
}
doDependencyCheck


#=================== Choice: Branch (Currently unused and simply skipped) ===================


# Bypass Branch choice and choose master. Because it's the only branch right now.
CHOICE_BRANCH=$DEFAULT_BRANCH

### Inactive code start. ###
inactiveCode ()
{

echo "
你可以选择3个分支:
* (S)Stable:   稳定版分支.

* (T)Testing:  测试版分支. 如果使用该分支版本遇到了一些bug，那么可以进行报告

* (D)Dev:      开发版分支(目前分支), 包含一些新功能或特性
"


printf %s "选择分支(s/t/d): "
read CHOICE_BRANCH
case $CHOICE_BRANCH in
	s|S)
		errorOther "抱歉，目前还没有稳定版分支，请使用测试版分支."
		;;
	t|T)
		CHOICE_BRANCH="testing"
		;;
	d|D)
		CHOICE_BRANCH="master"
		;;
	*)
		errorInput
		;;
esac

}
### Inactive code end. ###


#=================== Choice: Compile mode ===================


if [ $STATE_INTERACTIVE -eq 1 ]; then
	echo "
	选择编译模式:
	* (R)Release: 正常编译.

	* (D)Debug:   编译时输出调试信息.

	"

	printf %s "选择编译模式: (r/d) (默认: \"$DEFAULT_BUILDTYPE\"): "
	read CHOICE_BUILDTYPE
	case $CHOICE_BUILDTYPE in
		d|D)
			CHOICE_BUILDTYPE="Debug"
			;;
		r|N)
			CHOICE_BUILDTYPE="Release"
			;;
	esac
fi

if [ -z "$CHOICE_BUILDTYPE" ]; then # No buildtype specified.
	CHOICE_BUILDTYPE="$DEFAULT_BUILDTYPE"
fi


#=================== Choice: Thread amount ===================



numberOfThreads()
{
	KERNEL=`uname -s`

	if [ "$KERNEL" = "Linux" ] || [ "$KERNEL" = "Darwin" ]; then
		echo `getconf _NPROCESSORS_ONLN`
	elif [ "$KERNEL" = "FreeBSD" ]; then
		echo `getconf NPROCESSORS_ONLN`
	else
		echo "unknown"
	fi
}

CPU_THREAD_COUNT=`numberOfThreads`

if [ $STATE_INTERACTIVE -eq 1 ]; then
	echo ""
	echo "选择编译时的线程."

	if [ "$CPU_THREAD_COUNT" = "unknown" ]; then
		echo "无法检测CPU线程数."
	elif [ "$CPU_THREAD_COUNT" -eq 1 ]; then
		echo "你有1个CPU线程数."
	else
		echo "你有$CPU_THREAD_COUNT个CPU线程数."
	fi

	#echo "If you have enough RAM, it is wise to choose your CPU's thread count. "
	#echo "Otherwise choose lower. Old Raspberry Pis should choose 1. If in doubt, choose 1."
	printf %s "请输入编译时要使用的线程数 (默认: $DEFAULT_THREADS): "
	read CHOICE_THREADS
fi

if [ -z "$CHOICE_THREADS" ] 2> /dev/null; then
	CHOICE_THREADS="$DEFAULT_THREADS"
elif [ "$CHOICE_THREADS" = "AUTO" ] 2> /dev/null; then
	if [ $CPU_THREAD_COUNT = "unknown" ]; then
		CHOICE_THREADS="$DEFAULT_THREADS"
		echo "警告: 无法检测线程数，将会使用默认值($DEFAULT_THREADS)" >&2
	else
		CHOICE_THREADS="$CPU_THREAD_COUNT"
	fi
elif [ "$CHOICE_THREADS" -lt 0 ] 2> /dev/null; then
	errorInput
fi

#=================== Print settings summary  ===================


if [ "$STATE_NEW" = 1 ]; then
	previousCompilation="Not detected. We are assuming this is the first compile.sh run."
else
	previousCompilation="Detected. This should make fetching and compiling faster."
fi

THREAD_WARNING=""
if [ "$CPU_THREAD_COUNT" != "unknown" ] && [ "$CPU_THREAD_COUNT" -lt "$CHOICE_THREADS" ]; then
	THREAD_WARNING=" - 警告：分配的线程数超过了CPU线程数"
fi

echo ""
echoInt "#### Settings Summary ####"
echo "编译类型:           " "$CHOICE_BUILDTYPE"
echo "分支:               " "$CHOICE_BRANCH" "(Currently the only choice)"
echo "编译时使用的线程数: " "$CHOICE_THREADS$THREAD_WARNING"
echo "CPU线程数:          " "$CPU_THREAD_COUNT"
echo "Previous compilation: " "$previousCompilation"
echo "上游链接:           " "$UPSTREAM_LINK"
echo "上游仓库:           " "$UPSTREAM_REPO"

if [ "$DRY_RUN" = "yes" ]; then
	echo "This is a dry run. Exiting now."
	exit 0;
fi

# Ask the user's permission to connect to the net.
if [ $STATE_INTERACTIVE -eq 1 ]; then
	echo
	echo "当按下ENTER, 该脚本将会连接到$UPSTREAM_LINK"
	echo "进行检查更新和/或拉取代码. 然后会编译程序"
	echo "如果你之前编译过, make sure you're in the proper directory and that \"Previous compilation\" is detected."
	printf $s "按下ENTER继续... "
	read dummy
fi


#=================== Code download / update via git ===================


echoInt
echoInt " --- 正在下载Cuberite的源码，从 $CHOICE_BRANCH 分支..."


if [ $STATE_NEW -eq 1 ]; then
	# Git: Clone.
	echo " --- 似乎是第一次运行, 代码克隆中..."
	git clone  --depth 1 "$UPSTREAM_LINK" -b "$CHOICE_BRANCH" || errorGit "git clone  --depth 1 $UPSTREAM_LINK -b $CHOICE_BRANCH"
	cd cuberite_flmp
else
	# Git: Fetch.
	echo " --- 正在更新 $CHOICE_BRANCH 分支..."
	git fetch "$UPSTREAM_REPO" "$CHOICE_BRANCH" || errorGit "git fetch $UPSTREAM_REPO $CHOICE_BRANCH"
	git checkout "$CHOICE_BRANCH" || errorGit "git checkout $CHOICE_BRANCH"
	git merge "$UPSTREAM_REPO"/"$CHOICE_BRANCH" || errorGit "git merge $UPSTREAM_REPO/$CHOICE_BRANCH"
fi

# Git: Submodules.
echo " --- 正在更新子模块..."
git submodule sync
git submodule update --init


#=================== 编译通过cmake和make ===================


# Cmake.
echo " --- 正在运行cmake..."
if [ ! -d build-cuberite ]; then mkdir build-cuberite; fi
cd build-cuberite
cmake .. -DCMAKE_BUILD_TYPE="$CHOICE_BUILDTYPE" || errorCompile "cmake .. -DCMAKE_BUILD_TYPE=$CHOICE_BUILDTYPE"


# Make.
echo " --- 编译中..."
make -j "$CHOICE_THREADS" || errorCompile "make -j $CHOICE_THREADS"
echo


#=================== Print success message ===================


cd Server
echo
echo "-----------------"
echo "编译成功!"
echo
echo "Cuberite awaits you at:"
echo "$PWD/cuberite_flmp"

cd ../..
echo "
你可以执行该命令来更新Cuberite:
$PWD/compile_cn.sh

Enjoy :)"
exit 0


#=================== Windows fallback ===================


# Called via hack in line 2.
:windows_detected
@echo off
cls
echo 该脚本目前不支持Windows.
echo 你可以从该链接下载二进制文件: https://cuberite.org/
echo 你也可以手动为Windows平台编译. 转到: https://github.com/cuberite/cuberite
rem windows_exit
goto :EOF
}
